/**
* \file Vector3D.h
* \brief Header of class Vector3D
*/

#ifndef VECTOR3D_H
#define VECTOR3D_H

#include "Maths/precision.h"
#include <iostream>
#include <cmath>


namespace SimPhy
{

/**
 * \class Vector3D
 * \brief Holds a vector in 3 dimensions. Four data members are allocated
 * to ensure alignment in an array.
 * \note This class contains a lot of inline methods for basic
 * mathematics. The implementations are included in the header
 * file.
 */
class Vector3D
{
public:

    /** The default constructor creates a zero vector. */
    Vector3D();

    /**
     *  The explicit constructor creates a vector with the given components
     *  \param Value along the x axis.
     *  \param Value along the y axis.
     *  \param Value along the z axis.
     */
    Vector3D(real const x,  real const y = 0, real const z = 0);

    /** Accessor, \return the ith component or the third component if i>2 */
    real operator[](unsigned int i) const;
    /** Mutator, change the ith component or the third component if i>2 */
    real& operator[](unsigned int i);

    /** Adds the given vector to this vector and returns a reference to this vector. */
    Vector3D& operator+=(Vector3D const& vector);

    /** Subtracts the given vector from this vector and returns a reference to this vector. */
    Vector3D& operator-=(Vector3D const& vector);


    /** Multiplies this vector's coordinates by the given scalar, and returns a reference to this vector. */
    Vector3D& operator*=(real const scalar);


    /** Do the cross products of the vectors and returns a reference to the result vector */
    Vector3D& operator^=(Vector3D const& vector);

    /** Zero all the components of the vector. */
    void zero();

    /** \return The squared euclidean norm of the vector */
    real squaredLenght() const;

    /** \return The euclidean norm of the vector */
    real lenght() const;

    /** Turns a non-zero vector into a unit vector */
    void normalize();





private:
    real m_components[4]; /** Holds the components of the vector. */
                          /** Four floating-point values sit more cleanly in memory than three. */

};


/** Writes the given vector to the given stream and returns a reference to the stream. */
std::ostream& operator<<( std::ostream &stream, Vector3D const& vector );
/** Reads a 3D vector from the given stream into the given vector and returns a reference to the stream. */
std::istream& operator>> ( std::istream &stream, Vector3D &vector );

/** Returns true if v1 is equal to v2; otherwise returns false. This operator uses an exact floating-point comparison.*/
bool operator==(Vector3D const& v1, Vector3D const& v2);
/** Returns true if v1 is not equal to v2; otherwise returns false. This operator uses an exact floating-point comparison. */
bool operator!=(Vector3D const& v1, Vector3D const& v2);



/** Returns a Vector3D object that is the sum of the given vectors, v1 and v2; each component is added separately. */
Vector3D operator+(Vector3D const& v1, Vector3D const& v2);
/** Returns a Vecotr3D object that is formed by subtracting v2 from v1; each component is subtracted separately. */
Vector3D operator-(Vector3D const& v1, Vector3D const& v2);

/** Returns a copy of the given vector, multiplied by the given scalar to the right */
Vector3D operator*(Vector3D const& vector, real const scalar);
/** Returns a copy of the given vector, multiplied by the given scalar to the left */
Vector3D operator*(real const scalar, Vector3D const& vector);
/** Returns a copy of the given vector, multiplied by -1 */
Vector3D operator-(Vector3D const& vector);

/** Returns the dot product of the two vectors. */
real operator*(Vector3D const& v1, Vector3D const& v2);

/** Do the cross products of the vectors and returns the result vector */
Vector3D operator^(Vector3D const& v1, Vector3D const& v2);



/**
  * Make an orthonormal basis (a,b,c) where a keep his originial direction, with the given three vector.
  * a and b should not be parralel nor a zeroc vector.
  * If a and b are parralel or a zero vector, then they will not change and c will be the vector zero and false is returned,
  * else true is returned.
  */
bool makeOrthonormalBasis(Vector3D &a, Vector3D &b, Vector3D &c);



}
#endif // VECTOR3D_H
